package wechat.util.http;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpClientPoolUtil {

	private static final Logger logger = LoggerFactory.getLogger(HttpClientPoolUtil.class);
	
	public static final String UTF8 = "UTF-8";
	public static final String GBK = "GBK";
	public static final String GB2312 = "GB2312";
	
	public static final int SocketTimeout = 8 * 1000;
	public static final int ConnectTimeout = 8 * 1000;
	public static final int ConnectionRequestTimeout = 8 * 1000;
	
	public static final int MaxTotal = 500;
	public static final int DefaultMaxPerRoute = 50;

	
	public static RequestConfig requestConfig = null;
	public static PoolingHttpClientConnectionManager connectionManager = null;
	
	static {
		getRequestConfig();
		getConnectionManager();
	}
	
	
	private static void getRequestConfig() {
		if (requestConfig == null) {
			RequestConfig Default = RequestConfig.DEFAULT;
			requestConfig = RequestConfig.copy(Default).setSocketTimeout(SocketTimeout).setConnectTimeout(ConnectTimeout)
					.setConnectionRequestTimeout(ConnectionRequestTimeout).setRedirectsEnabled(true).setCircularRedirectsAllowed(false).build();
		}
	}
	
	private static void getConnectionManager() {
		if (connectionManager != null) {
			connectionManager = new PoolingHttpClientConnectionManager();
			connectionManager.setMaxTotal(MaxTotal);
			connectionManager.setDefaultMaxPerRoute(DefaultMaxPerRoute);
		}
	}
	
	public static CloseableHttpClient getCloseableHttpClient(RequestConfig config) {
		HttpClientBuilder httpClientBuilder = HttpClients.custom().setConnectionManager(connectionManager);
		if (config == null) {
			httpClientBuilder.setDefaultRequestConfig(requestConfig);
		} else {
			httpClientBuilder.setDefaultRequestConfig(config);
		}
		return httpClientBuilder.build();
	}
	
	
	public static String post(String url, Map<String, String> param, Map<String, String> headers) throws ClientProtocolException, IOException {
		return post(url, param, headers, UTF8,null);
	}
	
	public static String post(String url, Map<String, String> param) throws ClientProtocolException, IOException {
		return post(url, param, null, UTF8,null);
	}
	
	public static String post(String url, Map<String, String> param,String charset) throws ClientProtocolException, IOException {
		return post(url, param, null, charset,null);
	}
	
	public static String post(String url,Map<String, String> param,Map<String, String> headers,String charset,RequestConfig config) throws ClientProtocolException, IOException{
		logger.info("request url : {}", url);
		logger.info("request param : {}", param);
		logger.debug("request headers : {}", headers);
		logger.debug("request charset : {}", charset);
		
		CloseableHttpClient httpclient = getCloseableHttpClient(config);
		
		HttpPost httpPost = new HttpPost(url);
		
		if (headers != null) {
			for (Entry<String, String> header : headers.entrySet()) {
				httpPost.addHeader(header.getKey(), header.getValue());
			}
		}

		List<NameValuePair> nvps = new ArrayList<NameValuePair>();
		if (param != null) {
			for (Entry<String, String> form : param.entrySet()) {
				nvps.add(new BasicNameValuePair(form.getKey(), form.getValue()));
			}
		}
		
		httpPost.setEntity(new UrlEncodedFormEntity(nvps,charset));
		
		CloseableHttpResponse response = httpclient.execute(httpPost);
		String respStr = null;

		try {
			logger.info("response StatusLine : {}", response.getStatusLine());
			
		    HttpEntity entity = response.getEntity();
		    respStr = EntityUtils.toString(entity,charset);
		    logger.info("response entity : {}", respStr);
		    
		    EntityUtils.consume(entity);
		} finally {
		    response.close();
		    httpclient.close();
		}
		
		return respStr;
	}
	

	public static String post(String url,String param,Map<String, String> headers) throws ClientProtocolException, IOException{
		return post( url, param, headers,UTF8,null);
		
	}
	
	public static String post(String url,String param,String charset) throws ClientProtocolException, IOException{
		return post(url, param, null, charset,null);
		
	}
	
	public static String post(String url,String param) throws ClientProtocolException, IOException{
		return post(url, param, null, UTF8,null);
		
	}
	
	public static String post(String url,String param,Map<String, String> headers,String charset,RequestConfig config) throws ClientProtocolException, IOException{
		logger.info("request url : {}", url);
		logger.info("request param : {}", param);
		logger.debug("request headers : {}", headers);
		logger.debug("request charset : {}", charset);
		
		CloseableHttpClient httpclient = getCloseableHttpClient(config);
		
		HttpPost httpPost = new HttpPost(url);
		if (headers != null) {
			for (Entry<String, String> header : headers.entrySet()) {
				httpPost.addHeader(header.getKey(), header.getValue());
			}
		}

		httpPost.setEntity(new StringEntity(param, charset));
		
		CloseableHttpResponse response = httpclient.execute(httpPost);
		String respStr = null;

		try {
			logger.info("response StatusLine : {}", response.getStatusLine());
			
		    HttpEntity entity = response.getEntity();
		    respStr = EntityUtils.toString(entity,charset);
		    logger.info("response entity : {}", respStr);
		    
		    EntityUtils.consume(entity);
		} finally {
		    response.close();
		    httpclient.close();
		}
		
		return respStr;
		
	}
	
	
	public static String get(String url) throws ClientProtocolException, IOException{
		return get(url,null,UTF8,null);
	}
	
	public static String get(String url,Map<String, String> headers) throws ClientProtocolException, IOException{
		return get(url,headers,UTF8,null);
	}
	
	public static String get(String url,String charset) throws ClientProtocolException, IOException{
		return get(url,null,charset,null);
	}
	
	public static String get(String url,Map<String, String> headers,String charset,RequestConfig config) throws ClientProtocolException, IOException{
		logger.info("request url : {}", url);
		
		CloseableHttpClient httpclient = getCloseableHttpClient(config);
		
		HttpGet httpGet = new HttpGet(url);
		if (headers != null) {
			for (Entry<String, String> header : headers.entrySet()) {
				httpGet.addHeader(header.getKey(), header.getValue());
			}
		}
		
		CloseableHttpResponse response = httpclient.execute(httpGet);
		String respStr = null;
		try {
			logger.info("response StatusLine : {}", response.getStatusLine());
			
		    HttpEntity entity = response.getEntity();
		    respStr = EntityUtils.toString(entity,charset);
		    logger.info("response entity : {}", respStr);
		    
		    EntityUtils.consume(entity);
		} finally {
		    response.close();
		    httpclient.close();
		}
		
		return respStr;
	}
}
